﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;
using Tesla.Graphics;

namespace TeslaSamples {
    public partial class SampleBrowser : Form {
        public SampleBrowser() {
            InitializeComponent();
            BuildSampleTree();
            sampleDescText.Rtf = Resources.StartDescription;
            sourceText.Rtf = Resources.StartDescription;
        }

        private void BuildSampleTree() {
            Assembly assembly = Assembly.GetEntryAssembly();
            Type[] types = assembly.GetTypes();
            List<Type> list = new List<Type>();
            Type appClass = typeof(IApp);
            Dictionary<String, List<AppItem>> namespaces = new Dictionary<string, List<AppItem>>();
            foreach(Type type in types) {
                String name = type.Namespace;
                if(appClass.IsAssignableFrom(type) && !type.IsInterface && !type.IsAbstract) {
                    int index = name.LastIndexOf(".");
                    if(index > 0) {
                        name = name.Substring(index + 1);
                    }
                    List<AppItem> itemList;
                    if(namespaces.TryGetValue(name, out itemList)) {
                        itemList.Add(new AppItem(type));
                    } else {
                        itemList = new List<AppItem>();
                        itemList.Add(new AppItem(type));
                        namespaces.Add(name, itemList);
                    }
                }
            }

            foreach(String name in namespaces.Keys) {
                TreeNode node = new TreeNode(name);
                List<AppItem> itemList = namespaces[name];
                foreach(AppItem item in itemList) {
                    TreeNode child = new TreeNode(item.ToString());
                    child.Tag = item;
                    node.Nodes.Add(child);
                }
                sampleTree.Nodes.Add(node);
            }
            sampleTree.Sort();
            sampleTree.ExpandAll();
            sampleLabel.Text = String.Format("Choose sample to run ({0} total)", sampleTree.GetNodeCount(true) - sampleTree.GetNodeCount(false));
        }

        private void OnQuit(object sender, MouseEventArgs e) {
            Application.Exit();
        }

        private void OnGo(object sender, MouseEventArgs e) {
            AppItem appItem = (AppItem) sampleTree.SelectedNode.Tag;
            if(appItem == null) {
                return;
            }

            Type type = appItem.AppType;

            String[] res = ((String)resolutionList.SelectedItem).Split('x');

            int width = int.Parse(res[0]);
            int height = int.Parse(res[1]);

            String depthFormat = depthList.SelectedItem as String;
            DepthFormat depthEnum = DepthFormat.None;
            switch(depthFormat) {
                case "None":
                    depthEnum = DepthFormat.None;
                    break;
                case "Depth16":
                    depthEnum = DepthFormat.Depth16;
                    break;
                case "Depth24":
                    depthEnum = DepthFormat.Depth24;
                    break;
                case "Depth32":
                    depthEnum = DepthFormat.Depth32;
                    break;
                case "Depth24Stencil8":
                    depthEnum = DepthFormat.Depth24Stencil8;
                    break;
            }

            PresentationParameters pp = new PresentationParameters();
            pp.BackBufferFormat = SurfaceFormat.Color;
            pp.BackBufferWidth = width;
            pp.BackBufferHeight = height;
            pp.DepthStencilFormat = depthEnum;
            pp.MultiSampleCount = int.Parse(sampleBox.Text);
            if(vSyncCheck.Checked) {
                pp.PresentInterval = PresentInterval.One;
            } else {
                pp.PresentInterval = PresentInterval.Immediate;
            }

            pp.IsFullScreen = fullScreenCheck.Checked;

            String samples = sampleBox.SelectedItem as String;
            switch(samples) {
                case "0":
                    pp.MultiSampleCount = 0;
                    break;
                case "2":
                    pp.MultiSampleCount = 2;
                    break;
                case "4":
                    pp.MultiSampleCount = 4;
                    break;
                case "8":
                    pp.MultiSampleCount = 8;
                    break;
            }

            String platString = rendererSelection.SelectedItem as String;
            RenderSystemPlatform platform = RenderSystemPlatform.None;
            switch(platString) {
                case "Direct3D 10":
                    platform = RenderSystemPlatform.Direct3D10;
                    break;
                case "XNA 4.0":
                    platform = RenderSystemPlatform.XNA4;
                    break;
            }
             
            if(platform == RenderSystemPlatform.None) {
                MessageBox.Show("No valid renderer!");
            } else {

                ThreadStart threadStart = new ThreadStart(delegate() {
                    ConstructorInfo cinfo = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, new Type[0], null);
                    IApp app = (IApp) cinfo.Invoke(null);
                    try {
                        app.Run(platform, pp);
                    } catch(Exception esc) {
                        if(esc.InnerException != null) {
                            MessageBox.Show("Error starting sample\n\n" + esc.Message + "\n\n" + esc.InnerException.Message + "\n\n" + esc.StackTrace);
                        } else {
                            MessageBox.Show("Error starting sample\n\n" + esc.Message + "\n\n" + esc.StackTrace);
                        }
                    } finally {
                        Tesla.Core.Engine.CleanUpResources();
                    }
                });

                Thread thread = new Thread(threadStart);
                thread.Start();

            }
        }

        private void SetValidPlatforms(AppDescriptionAttribute att) {
            rendererSelection.Items.Clear();
            rendererSelection.Text = "";
            if(att != null) {
                PlatformCapabilities flags = att.Platforms;
                if(flags == PlatformCapabilities.None) {
                    return;
                }
                if((flags & PlatformCapabilities.Direct3D10) == PlatformCapabilities.Direct3D10) {
                    rendererSelection.Items.Add("Direct3D 10");
                }
                if((flags & PlatformCapabilities.XNA4) == PlatformCapabilities.XNA4) {
                    rendererSelection.Items.Add("XNA 4.0");
                }
                rendererSelection.Text = (String) rendererSelection.Items[0];
            } 
        }

        private void LinkClicked(object sender, LinkClickedEventArgs e) {
            try {
                Process.Start("IExplore.exe", e.LinkText);
            } catch(Exception exc) {
                System.Diagnostics.Debug.WriteLine("Cannot start browser. " + exc.Message);
            }
        }

        private void SampleSelected(object sender, TreeNodeMouseClickEventArgs e) {
            AppItem app = e.Node.Tag as AppItem;
            if(app == null) {
                return;
            }
            AppDescriptionAttribute att = app.AppAttributes;
            SetValidPlatforms(att);

            if(att != null) {
                samplepic.Image = att.Thumbnail;
                sampleDescText.Rtf = att.RTFDescription;
                sourceText.Rtf = att.RTFSource;
            } else {
                samplepic.Image = Resources.DefaultImage;
                sampleDescText.Rtf = Resources.NoDescription;
                sourceText.Rtf = Resources.NoSourceCode;
            }
        }

        private void CopySource(object sender, EventArgs e) {
            Clipboard.SetText(sourceText.SelectedText, TextDataFormat.Text);
        }

        private void SelectAllSourceText(object sender, EventArgs e) {
            sourceText.SelectAll();
        }
    }
}
